﻿
Imports System.IO
Imports System.Reflection
Imports osi.root.connector
Imports osi.root.constants
Imports osi.root.envs
Imports osi.root.formation
Imports osi.root.utils
Imports osi.root.constants.filesystem
Imports osi.root.delegates

Friend Module host
    Public ReadOnly cases As vector(Of case_info) = Nothing

    Private Function existing_case(ByVal j As Type) As Boolean
        If cases.empty() Then
            Return False
        Else
            For i As UInt32 = 0 To CUInt(cases.size() - 1)
                If object_compare(cases(i).case.GetType(), j) = 0 Then
                    Return True
                End If
            Next
            Return False
        End If
    End Function

    Private Function accepted_type(ByVal j As Type) As Boolean
        assert(Not j Is Nothing)
        Return Not j.IsAbstract() AndAlso
               Not j.IsGenericType() AndAlso
               j.IsPublic() AndAlso
               Not strendwith(j.Name(), "_wrapper", False) AndAlso
               Not strsame(j.Name(), "delegate_case") AndAlso
               j.inherit(Of [case])() AndAlso
               Not existing_case(j)
    End Function

    Private Sub load_cases(ByVal path As String)
        Dim files() As String = Nothing
        files = Directory.GetFiles(path,
                                   strcat(multi_pattern_matching_character,
                                          extension_prefix,
                                          extensions.dynamic_link_library))
        If Not isemptyarray(files) Then
            For i As Int64 = 0 To files.Length() - 1
                Try
                    AppDomain.CurrentDomain().Load(AssemblyName.GetAssemblyName(files(i)))
                Catch ex As Exception
                    raise_error(error_type.exclamation, "failed to load assembly ", files(i), ", ex ", ex.Message())
                End Try
            Next
        End If

        For Each i In AppDomain.CurrentDomain().GetAssemblies()
            Try
                For Each j In i.GetTypes()
                    If accepted_type(j) Then
                        cases.push_back(New case_info(j.Name(), alloc(Of [case])(j)))
                        raise_error("loaded case ", j.Name())
                    End If
                Next
            Catch ex As Exception
                raise_error(error_type.exclamation,
                            "failed to load types from assembly ",
                            i.FullName(),
                            ", ex ",
                            ex.Message())
            End Try
        Next
    End Sub

    Sub New()
        assert(Not strstartwith(extensions.dynamic_link_library, extension_prefix, False))
        cases = New vector(Of case_info)()
        load_cases(Environment.CurrentDirectory())
        If Not Environment.CurrentDirectory().path_same(application_directory) Then
            load_cases(application_directory)
        End If
        assert(cases.size() > 0)
    End Sub

    Private Function [select](ByVal selector As vector(Of String), ByVal name As String) As Boolean
        Return selector Is Nothing OrElse selector.size() = 0 OrElse name.match_pattern(selector)
    End Function

    Public Function foreach(ByVal d As _do(Of case_info, Boolean, Boolean)) As Boolean
        If d Is Nothing Then
            Return False
        Else
            Return cases.foreach(d)
        End If
    End Function

    Public Function foreach(ByVal d As _do(Of case_info, Boolean)) As Boolean
        Return utils.foreach(AddressOf foreach, d)
    End Function

    Public Function foreach(ByVal d As void(Of case_info)) As Boolean
        Return utils.foreach(AddressOf foreach, d)
    End Function

    Public Sub clear_selection()
        foreach(Sub(ByRef x) x.finished = False)
    End Sub

    Public Function run(Optional ByVal selector As vector(Of String) = Nothing) As Int32
        Dim r As Int32 = 0
        clear_selection()
        foreach(Sub(ByRef x)
                    If [select](selector, x.name) Then
                        r += 1
                    Else
                        x.finished = True
                    End If
                End Sub)

        host_run.run()
        Return r
    End Function
End Module
